# @Version        : 1.0
# @Update Time    : 2025/4/8 21:34
# @File           : codegen.py
# @IDE            : PyCharm
# @Desc           : 文件描述信息
# codegen.py
from jinja2 import Environment, FileSystemLoader
from pathlib import Path
from fastapi_utils.camelcase import snake2camel, camel2snake


class GeneratorTools:
    def __init__(self, template_dir="templates", output_dir="output"):
        self.output_dir = Path(output_dir)
        self.output_dir.mkdir(parents=True, exist_ok=True)
        self.env = Environment(
            loader=FileSystemLoader(template_dir),
            trim_blocks=True,
            lstrip_blocks=True,
            autoescape=False,
        )

        # 类型映射配置
        self.type_mapping = {
            "str": {"sa": "String", "py": "str"},
            "int": {"sa": "Integer", "py": "int"},
            "bool": {"sa": "Boolean", "py": "bool"},
            "float": {"sa": "Float", "py": "float"},
            "text": {"sa": "Text", "py": "str"},
            "datetime": {
                "sa": "DateTime",
                "py": "datetime",
                "sa_args": "",
                "import": "from datetime import datetime",
            },
            "auto_now": {
                "sa": "DateTime",
                "py": "datetime",
                "sa_args": "",
                "server_default": "func.now()",
                "import": "from sqlalchemy import func",
            },
        }

        # 前端类型映射配置
        self.frontend_type_mapping = {
            "str": "string",
            "int": "number",
            "bool": "boolean",
            "float": "number",
            "text": "string",
            "datetime": "Date",
            "auto_now": "Date",
        }

    def generate_crud(
        self,
        model_name: str,
        tags: str,
        describe: str,
        permissions: str,
        fields: list,
    ):
        # 处理字段的SA参数和附加属性
        processed_fields = []
        sa_imports = set()
        need_func = False
        need_datetime = False

        for field in fields:
            # 类型映射处理
            field_type = field["type"].lower()
            mapped = self.type_mapping.get(field_type, {"sa": "String", "py": "str"})

            # 处理SA类型参数（如String长度）
            sa_args = ""
            if field.get("length"):
                sa_args = f"({field['length']})"
            elif "sa_args" in mapped:
                sa_args = mapped["sa_args"]

            # 处理服务器默认值
            server_default = field.get("server_default")
            if not server_default and "server_default" in mapped:
                server_default = mapped["server_default"]
                if "func" in server_default:
                    need_func = True

            # 处理类型相关导入
            if "datetime" in mapped["py"]:
                need_datetime = True

            default_value = field.get("default_value", None)
            required = field.get("required", True)

            processed_fields.append(
                {
                    "name": field["name"],
                    "py_type": mapped["py"],
                    "sa_type": mapped["sa"],
                    "sa_args": sa_args,
                    "py_type_anno": f"{mapped['py']} | None"
                    if field.get("nullable")
                    else mapped["py"],
                    "is_key": field.get("is_key", False),
                    "nullable": field.get("nullable"),
                    "description": field.get("description", ""),
                    "server_default": server_default,
                    "sort_order": field.get("sort_order"),
                    "default_value": default_value,
                    "required": required,
                }
            )

            # 收集需要导入的SA类型
            sa_imports.add(mapped["sa"].split("(")[0].strip())

        # 构造模板上下文
        context = {
            "model_name": snake2camel(model_name),  # 将下划线转驼峰
            "table_name": camel2snake(model_name),  # 将驼峰转下划线
            "fields": processed_fields,
            "sa_imports": sorted(sa_imports),
            "need_func": need_func,
            "need_datetime": need_datetime,
            "tags": tags,
            "permissions": permissions,
            "comment": describe,
        }

        # 定义模板映射
        templates = {
            "backend/controller.py.j2": "controller.py",
            "backend/model.py.j2": "model.py",
            "backend/schema.py.j2": "schema.py",
            "backend/service.py.j2": "service.py",
            "backend/repository.py.j2": "repository.py",
        }
        # 判断路径是否存在，不存在则创建
        backend_output_dir = self.output_dir / "backend"
        backend_output_dir.mkdir(parents=True, exist_ok=True)
        try:
            # 渲染模板
            for template_file, output_file in templates.items():
                template = self.env.get_template(template_file)
                content = template.render(**context)

                with open(
                    backend_output_dir / f"{camel2snake(model_name)}_{output_file}",
                    "w",
                    encoding="utf-8",
                ) as f:
                    f.write(content)

            print(f"CRUD代码已生成到 {self.output_dir.absolute()}")
        except Exception as e:
            print(f"生成CRUD代码出错：{e}")

    # 新增生成前端代码的方法
    def generate_frontend(
        self, model_name: str, desc: str, columns: list, base_url: str
    ):
        # 构造模板上下文
        processed_columns = []
        for column in columns:
            # 使用前端类型映射
            frontend_type = self.frontend_type_mapping.get(column["type"], "any")
            processed_columns.append(
                {
                    "name": snake2camel(column["name"], True),
                    "type": frontend_type,
                    "description": column.get("description", ""),
                    "is_key": column.get("is_key", False),
                    "default_value": column.get("default_value", None),
                    "required": column.get("required", True),
                }
            )

        context = {
            "model_name": snake2camel(model_name),  # 将下划线转驼峰
            "table_name": camel2snake(model_name),  # 将驼峰转下划线
            "columns": processed_columns,
            "desc": desc,
            "base_url": base_url,
        }

        # 定义模板映射
        templates = {
            "frontend/index.vue.j2": "index.vue",
            "frontend/modules/operate-drawer.vue.j2": f"modules/{camel2snake(model_name)}operate-drawer.vue",  # 添加 operate-drawer.vue.j2 模板
            # 类型模板
            "frontend/types.ts.j2": "types.ts",
            # 请求模板
            "frontend/request.ts.j2": f"{camel2snake(model_name)}.ts",
        }
        # 判断路径是否存在，不存在则创建
        frontend_output_dir = self.output_dir / "frontend" / "modules"
        frontend_output_dir.mkdir(parents=True, exist_ok=True)
        try:
            # 渲染模板
            for template_file, output_file in templates.items():
                print(f"正在生成 {output_file}")
                template = self.env.get_template(template_file)
                content = template.render(**context)

                with open(
                    self.output_dir / "frontend" / output_file, "w", encoding="utf-8"
                ) as f:
                    f.write(content)

            print(f"前端代码已生成到 {self.output_dir.absolute()}")
        except Exception as e:
            print(f"生成前端代码出错：{e}")


if __name__ == "__main__":
    # 字段配置示例
    fields = [
        {
            "name": "field_name",
            "type": "str",
            "length": 50,
            "description": "字段名称",
            "nullable": False,
            "sort_order": 1,
            "required": True,
        },
        {
            "name": "field_type",
            "type": "str",
            "length": 50,
            "description": "类型",
            "nullable": True,
            "sort_order": 2,
            "required": False,
        },
        {
            "name": "field_description",
            "type": "str",
            "length": 50,
            "description": "字段描述",
            "nullable": True,
            "sort_order": 3,
            "required": False,
        },
        {
            "name": "field_default_value",
            "type": "str",
            "length": 50,
            "description": "默认值",
            "nullable": True,
            "sort_order": 4,
            "required": False,
        },
        {
            "name": "field_is_key",
            "type": "bool",
            "length": 50,
            "description": "是否主键",
            "nullable": True,
            "sort_order": 5,
            "required": False,
        },
        {
            "name": "field_is_nullable",
            "type": "bool",
            "length": 50,
            "description": "是否允许为空",
            "nullable": True,
            "sort_order": 6,
            "required": False,
        },
        {
            "name": "field_is_unique",
            "type": "bool",
            "length": 50,
            "description": "是否唯一",
            "nullable": True,
            "sort_order": 7,
            "required": False,
        },
        {
            "name": "field_is_auto_increment",
            "type": "bool",
            "length": 50,
            "description": "是否自增",
            "nullable": True,
            "sort_order": 8,
            "required": False,
        },
    ]

    generator = GeneratorTools(
        template_dir=r"D:\Apps\Fork\rapid-admin-system\rapid-api\src\code_generation\templates",
        output_dir=r"D:\Apps\Fork\rapid-admin-system\rapid-api\src\code_generation\templates\generated",
    )
    generator.generate_crud(
        model_name="CodeGenerator",
        tags="代码生成管理",
        permissions="code:generator",
        describe="代码生成",
        fields=fields,
    )
    generator.generate_frontend(
        model_name="CodeGenerator",
        desc="代码生成管理",
        columns=fields,
        base_url="/codegen",
    )
